package com.ruoyi.common.utils;

import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.Java2DFrameConverter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

/**
 * 若依框架专用视频帧截取工具类
 * 支持虚拟路径转物理路径，从视频中提取指定时间点的帧并保存为图片
 */

@Component
public class VideoFrameCapturer {

    // 从配置文件读取实际上传物理路径（如 D:/ruoyi/uploadPath）
    @Value("${ruoyi.profile}")
    private String uploadPhysicalPrefix;

    // 若依默认虚拟路径前缀
    public static final String VIRTUAL_PREFIX = "/profile/upload/";
    public String getUploadPhysicalPrefix() {
        return uploadPhysicalPrefix;
    }
    /**
     * 将虚拟路径转换为实际物理路径
     * @param virtualPath 前端传来的虚拟路径
     * @return 实际物理路径
     */
    private String getPhysicalPath(String virtualPath) {
        if (virtualPath == null || !virtualPath.startsWith(VIRTUAL_PREFIX)) {
            throw new IllegalArgumentException("无效的虚拟路径：" + virtualPath);
        }
        
        // 截取相对路径部分并拼接物理路径
        String relativePath = virtualPath.substring(VIRTUAL_PREFIX.length());
        return uploadPhysicalPrefix + File.separator +"upload" + File.separator +relativePath;
    }

    /**
     * 从视频中截取指定时间点的帧（使用虚拟路径）
     * @param virtualVideoPath 视频虚拟路径
     * @param timeInSeconds 截取时间点(秒)
     * @param imageFormat 图片格式(jpg, png等)
     * @return 截取成功的图片物理路径，失败返回null
     */
    public String captureFrameByVirtualPath(String virtualVideoPath, double timeInSeconds, String imageFormat) {
        try {
            // 转换虚拟路径为物理路径
            String physicalVideoPath = getPhysicalPath(virtualVideoPath);
            
            // 生成输出图片路径（在视频同目录，文件名加_frame后缀）
            String outputImagePath = physicalVideoPath.substring(0, physicalVideoPath.lastIndexOf(".")) 
                    + "_frame." + imageFormat;
            
            // 执行帧截取
            if (captureFrame(physicalVideoPath, timeInSeconds, outputImagePath, imageFormat)) {
                return outputImagePath;
            }
            return null;
        } catch (Exception e) {
            System.err.println("帧截取失败: " + e.getMessage());
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 从视频中截取指定时间点的帧（使用物理路径）
     * @param videoPath 视频物理路径
     * @param timeInSeconds 要截取的时间点(秒)
     * @param outputImagePath 输出图片完整路径
     * @param imageFormat 图片格式
     * @return 是否截取成功
     */
    private boolean captureFrame(String videoPath, double timeInSeconds, 
                                String outputImagePath, String imageFormat) {
        // 验证视频文件是否存在
        File videoFile = new File(videoPath);
        if (!videoFile.exists() || !videoFile.isFile()) {
            System.err.println("视频文件不存在: " + videoPath);
            System.err.println("绝对路径: " + videoFile.getAbsolutePath());
            return false;
        }
        
        FFmpegFrameGrabber grabber = null;
        try {
            // 创建视频抓取器
            grabber = new FFmpegFrameGrabber(videoPath);
            grabber.start();
            
            // 获取视频总时长(秒)
            double totalDuration = grabber.getLengthInTime() / 1000000.0;
            
            // 检查时间是否在有效范围内
            if (timeInSeconds < 0 || timeInSeconds > totalDuration) {
                System.err.println("指定时间超出视频时长，总时长: " + totalDuration + "秒");
                return false;
            }
            
            // 跳转到指定时间点(微秒)
            grabber.setTimestamp((long)(timeInSeconds * 1000000));
            
            // 获取该时间点的帧
            Frame frame = grabber.grabImage();
            if (frame == null) {
                System.err.println("无法获取指定时间点的帧");
                return false;
            }
            
            // 转换为BufferedImage
            Java2DFrameConverter converter = new Java2DFrameConverter();
            BufferedImage bufferedImage = converter.getBufferedImage(frame);
            if (bufferedImage == null) {
                System.err.println("帧转换为图片失败");
                return false;
            }
            
            // 确保输出目录存在
            File outputFile = new File(outputImagePath);
            File outputDir = outputFile.getParentFile();
            if (outputDir != null && !outputDir.exists()) {
                outputDir.mkdirs();
            }
            
            // 保存为图片文件
            ImageIO.write(bufferedImage, imageFormat, outputFile);
            System.out.println("帧截取成功，保存至: " + outputFile.getAbsolutePath());
            return true;
            
        } catch (Exception e) {
            System.err.println("帧截取处理异常: " + e.getMessage());
            e.printStackTrace();
            return false;
        } finally {
            // 释放资源
            if (grabber != null) {
                try {
                    grabber.stop();
                    grabber.release();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    /**
     * 从视频虚拟路径获取时长（秒）
     * @param virtualVideoPath 视频虚拟路径（如 /profile/upload/2025/08/15/xxx.mp4）
     * @return 视频时长（秒），失败返回 -1
     */
    public int getVideoDurationByVirtualPath(String virtualVideoPath) {
        try {
            // 转换虚拟路径为物理路径
            String physicalVideoPath = getPhysicalPath(virtualVideoPath);
            // 调用物理路径获取时长的方法
            return getVideoDurationByPhysicalPath(physicalVideoPath);
        } catch (Exception e) {
            System.err.println("获取视频时长失败（虚拟路径）: " + e.getMessage());
            e.printStackTrace();
            return -1;
        }
    }

    /**
     * 从视频物理路径获取时长（秒）
     * @param physicalVideoPath 视频物理路径（如 D:/ruoyi/uploadPath/upload/2025/08/15/xxx.mp4）
     * @return 视频时长（秒），失败返回 -1
     */
    private int getVideoDurationByPhysicalPath(String physicalVideoPath) {
        // 验证视频文件是否存在（复用已有逻辑）
        File videoFile = new File(physicalVideoPath);
        if (!videoFile.exists() || !videoFile.isFile()) {
            System.err.println("视频文件不存在: " + physicalVideoPath);
            System.err.println("绝对路径: " + videoFile.getAbsolutePath());
            return -1;
        }

        FFmpegFrameGrabber grabber = null;
        try {
            // 创建视频抓取器并启动
            grabber = new FFmpegFrameGrabber(physicalVideoPath);
            grabber.start();

            // 获取视频总时长（微秒），转换为秒（四舍五入取整）
            long durationMicros = grabber.getLengthInTime();
            return (int) Math.round(durationMicros / 1000000.0); // 1秒 = 1,000,000微秒
        } catch (Exception e) {
            System.err.println("获取视频时长失败（物理路径）: " + e.getMessage());
            e.printStackTrace();
            return -1;
        } finally {
            // 释放资源（复用已有逻辑）
            if (grabber != null) {
                try {
                    grabber.stop();
                    grabber.release();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    // 测试方法
    public static void main(String[] args) {
        // 注意：实际使用时通过Spring注入，此处为演示手动设置物理路径
        VideoFrameCapturer capturer = new VideoFrameCapturer();
        capturer.uploadPhysicalPrefix = "D:/ruoyi/uploadPath/"; // 模拟配置注入
        
        // 虚拟路径示例（与前端传入路径一致）
        String virtualPath = "/profile/upload/2025/08/15/光年之外_20250815212017A001.mp4";
        
        // 截取第10秒的帧，保存为jpg格式
        String result = capturer.captureFrameByVirtualPath(virtualPath, 10, "jpg");
        if (result != null) {
            System.out.println("操作成功，图片路径：" + result);
        } else {
            System.out.println("操作失败");
        }
    }
}
    